import concurrent.futures
import logging

from flask import request, jsonify, Blueprint

import uuid

from api.contexts.rule_enum import RuleType
from api.service.rule_config_service import rule_manager
from api.service.rule_transfer_service import transform_result
from api.web.rule_config_controller import rule_storage
from core.rule.entities.variable_pool import VariablePool
from core.rule.entities.workflow_execution import WorkflowType
from core.rule.enums import UserFrom, InvokeFrom, SystemVariableKey
from core.rule.graph_engine import Graph
from core.rule.graph_engine.entities.event import NodeRunSucceededEvent
from core.rule.graph_engine.graph_engine import GraphEngine
from concurrent.futures import ThreadPoolExecutor

logger = logging.getLogger(__name__)

app = Blueprint('rule_trigger', __name__)

executor = ThreadPoolExecutor(max_workers=10)


@app.route('/rules/validate', methods=['POST'])
def execute_rules_validate():
    return execute_graph_batch()


@app.route('/execute-graph', methods=['POST'])
def execute_graph():
    """
       接收用户输入，查找 graph_config，**并发**执行所有匹配的图引擎。
    """
    user_input = request.get_json()
    if not user_input:
        return jsonify({"error": "请求体必须是 JSON 格式"}), 400

    mater_cate = user_input.get("data")
    meta = user_input.get("meta")
    if mater_cate.get("mater_cate", mater_cate.get("tree_id")) is None:
        return jsonify({"error": "用户输入中缺少 'mater_cate' 字段"}), 400
    data = execute(mater_cate, mater_cate.get("mater_cate", mater_cate.get("tree_id")), meta.get("operator", ""),
                   meta.get("rule_id", []))
    return jsonify({
        "code": "200",
        "message": f"执行完成",
        "data": data,
    }), 200


@app.route('/execute-graph-batch', methods=['POST'])
def execute_graph_batch():
    """
         接收用户输入，查找 graph_config，**并发**执行所有匹配的图引擎。
    """
    user_input = request.get_json()
    if not user_input:
        return jsonify({"error": "请求体必须是 JSON 格式"}), 400

    data = user_input.get("data")
    meta = user_input.get("meta")
    datas = []
    for mater_item in data:
        mate_cate = mater_item.get("mater_cate", mater_item.get("tree_id"))
        if mater_item.get("materialtype ") == 'E':
            mate_cate = ""
        datas.append(
            execute(mater_item, mate_cate, meta.get("operator", ""),
                    meta.get("rule_id", [])))
    return jsonify({
        "code": "200",
        "message": f"执行完成",
        "data": datas,
    }), 200


def execute(mater_item: dict, mater_cate: str, user: str, rules: []):
    data = {"fact": mater_item}
    try:
        if rules:
            config_list = [config for code in rules
                           if (config := rule_storage.get_dict_by_code(code)) is not None]
        else:
            config_list = rule_storage.get_dicts(mater_cate)
            config_list_common = rule_storage.get_dicts(RuleType.RULE_COMMON_CATE.code)
            if len(config_list_common) > 0:
                config_list = config_list.extend(config_list_common)
        if not config_list:
            logger.info(f"未找到 mater_cate 为 '{mater_cate}' 的 rule 配置")
    except KeyError:
        logger.error({"error": f"配置存储中不存在类别 '{mater_cate}'"})
        return data
    except Exception as e:
        logger.error({"error": f"查找配置时发生错误: {str(e)}"})
        return data
    variable_pool = VariablePool(
        system_variables={
            SystemVariableKey.QUERY: mater_item.get("query", ""),
            SystemVariableKey.FILES: [],
            SystemVariableKey.CONVERSATION_ID: str(uuid.uuid4()),
            SystemVariableKey.USER_ID: user,
        },
        user_inputs=mater_item
    )
    try:
        future_to_config = {
            executor.submit(_run, config, variable_pool, user): config
            for config in config_list
        }

        all_results = []
        resultEvent = None
        for future in concurrent.futures.as_completed(future_to_config):
            result = future.result()
            for event in result.get("results"):
                if isinstance(event, NodeRunSucceededEvent) and event.route_node_state.node_id in ["answer"]:
                    rule_data = rule_manager.get(event.route_node_state.node_run_result.graph_config.get("rule_code"))
                    result = transform_result(rule_data, event.route_node_state.node_run_result.outputs["answer"],
                                              mater_item,
                                              resultEvent.route_node_state.node_run_result.inputs.get("conditions"))
                    if result:
                        all_results.append(result)
                elif isinstance(event, NodeRunSucceededEvent) and event.route_node_state.node_id in ["result"]:
                    resultEvent = event
        data["rules"] = all_results
        data["execution_id"] = str(uuid.uuid4())
    except Exception as e:
        logger.error(f"执行规则execute发生异常: {str(e)}")

    return data


def _run(config, variable_pool, user):
    try:
        graph = Graph.init(graph_config=config)
        engine = GraphEngine(
            tenant_id="1",
            app_id="1",
            workflow_type=WorkflowType.WORKFLOW,
            workflow_id="1",
            graph_config=config,
            user_id=user,
            user_from=UserFrom.ACCOUNT,
            invoke_from=InvokeFrom.SERVICE_API,
            call_depth=0,
            graph=graph,
            variable_pool=variable_pool,
            max_execution_steps=500,
            max_execution_time=1200,
        )

        items = []
        generator = engine.run()
        for item in generator:
            items.append(item)
        return {
            "status": "success",
            "config_id": config.get("id", "unknown"),  # 假设 config 有 id 字段
            "results": items
        }
    except Exception as e:
        logger.error(f"执行规则_run发生异常: {str(e)}")
        return {
            "status": "error",
            "config_id": config.get("id", "unknown"),
            "error": str(e)
        }


import atexit


@atexit.register
def shutdown_executor():
    executor.shutdown()
